<?php

namespace app\index\controller;
use app\common\controller\IndexBase;
use app\common\model\Config;
use app\common\model\GoodsMain;
use PayPal\Api\Amount;
use PayPal\Api\Details;
use PayPal\Api\Item;
use PayPal\Api\ItemList;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\PaymentExecution;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
use PayPal\Exception\PayPalConnectionException;
use think\Exception;
use think\facade\View;
use think\facade\Log;
use PayPal\Rest\ApiContext;
use PayPal\Auth\OAuthTokenCredential;
use app\common\model\Order as orderModel;

class Paypal extends IndexBase
{
    const clientId = 'AY00-3BpkJFLngt5MFQBcSpWuJZXHZqSqTEKZVpWDicsvPRDnJYGSk--92FkMXoDf7OXg5RanqeejXaz'; //ID
    const clientSecret = 'EJ1bOAzIxV2ynaPY8Nvk796uY2fEnnNGL5813rxPIo8zo52B1-WlHeilJDsLsWp-xljmykR2wkWoxiss'; //秘钥
    const accept_url = '/index/Paypal/Callback'; //返回地址
    protected $PayPal;
    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
        $this->PayPal = new ApiContext(
            new OAuthTokenCredential(
                self::clientId,
                self::clientSecret
            )
        );
        $this->PayPal->setConfig(
            array(
                'mode' => 'sandbox',
            )
        );
    }

    public function index()
    {
        $id = input("param.id/s", "");
        $orinfo = orderModel::find($id);

        if (!session("?user")) {
            $this->jump_error(lang('login error'));
        }

        if (empty($orinfo) || $orinfo['status'] != 0) {
            $this->jump_error(lang('fail'));
        }
        $product = input('product', 'goods');
        if (empty($product)) {
            $this->jump_error(lang('Product cannot be empty'));
        }

        $shipping = $orinfo['body']['all_carrier_price'];
        $price = $orinfo['money'] - $shipping;

        $description = input('description', 'buy goods');
        if (empty($description)) {
            $this->jump_error(lang('Description content cannot be empty'));
        }
        $this->pay($product, $price, $shipping, $description, $orinfo['out_trade_no'], 'USD');
    }

    /**
     * @param
     * $product 商品
     * $price 价钱
     * $shipping 运费
     * $description 描述内容
     */
    public function pay($product, $price, $shipping = 0, $description, $uniqid, $Currency)
    {
        $paypal = $this->PayPal;

        $total = $price + $shipping; //总价

        $payer = new Payer();
        $payer->setPaymentMethod('paypal');
        $item = new Item();
        $item->setName($product)->setCurrency($Currency)->setQuantity(1)->setPrice($price);

        $itemList = new ItemList();
        $itemList->setItems([$item]);

        $details = new Details();
        $details->setShipping($shipping)->setSubtotal($price);

        $amount = new Amount();
        $amount->setCurrency($Currency)->setTotal($total)->setDetails($details);

        $transaction = new Transaction();
        $transaction->setAmount($amount)->setItemList($itemList)->setDescription($description)->setInvoiceNumber($uniqid);
        //$transaction->setAmount($amount)->setItemList($itemList)->setDescription($description)->setInvoiceNumber(uniqid());

        $redirectUrls = new RedirectUrls();
        $appRoot = request()->domain(); // 去掉参数 true 将获得相对地址
        $uriRoot = preg_match('/\.php$/', $appRoot) ? dirname($appRoot) : $appRoot;
        $redirectUrls->setReturnUrl($uriRoot . self::accept_url . '?success=true')->setCancelUrl($uriRoot . self::accept_url . '/?success=false');

        $payment = new Payment();
        $payment->setIntent('sale')->setPayer($payer)->setRedirectUrls($redirectUrls)->setTransactions([$transaction]);

        try {
            $payment->create($paypal);
        } catch (PayPalConnectionException $e) {
            dump($e->getMessage());
            return $e->getMessage();
        }

        $approvalUrl = $payment->getApprovalLink();
        $this->redirect($approvalUrl);
        header("Location: {$approvalUrl}");
    }

    /**
     * 回调
     */
    public function Callback()
    {
        //商品栏目
        //外链
        $appRoot = request()->domain(); // 去掉参数 true 将获得相对地址
        $uriRoot = preg_match('/\.php$/', $appRoot) ? dirname($appRoot) : $appRoot;
        // 写入缓存
        $global = cache('Config');
        if (empty($global)) {
            $result = Config::select();
            $data = [];
            foreach ($result as $val) {
                $data[$val['code']] = $val['value'];
            }
            cache('Config', $data);
            $global = $data;
        }

        $success = trim($_GET['success']);

        if ($success == 'false' && !isset($_GET['paymentId']) && !isset($_GET['PayerID'])) {
            $pay =  lang('Cancel payment');
            View::assign('pay',$pay);
            return View::fetch();
        }

        $paymentId = trim($_GET['paymentId']);
        $PayerID = trim($_GET['PayerID']);

        if (!isset($success, $paymentId, $PayerID)) {
            $pay = lang('Payment failed');
            View::assign('pay',$pay);

            return View::fetch();
        }

        if ((bool)$_GET['success'] === 'false') {
            $pay =   lang('Payment failed');
            View::assign('pay',$pay);

            return View::fetch();
        }

        $payment = Payment::get($paymentId, $this->PayPal);
        $execute = new PaymentExecution();
        $execute->setPayerId($PayerID);
        try {
            $orderinfo = $payment->execute($execute, $this->PayPal);
            $order_no = $orderinfo->transactions[0]->invoice_number;
            $orinfo = OrderModel::where(['out_trade_no' => $order_no])->find();
            if ($orinfo['status'] != 0) {
                $pay =  lang('Order status error');
                View::assign('pay',$pay);
                return View::fetch();
            }
            $where['status'] = 1;
            $where['pay_time'] = time();
            $orinfo->save($where);
            $orinfo->log()->save([
                "create_time" => time(),
                "title" => "支付成功"
            ]);

            foreach ($orinfo["body"]["goods"] as $item) {
                $goods = \app\common\model\Goods::find($item['goods']["id"]);
                $goods->sale += $item['num'];

                if (!empty($item['main'])) {
                    $main = GoodsMain::find($item['main']['id']);
                    if ($main) {
                        $main->stock -= $item['num'];
                        $main->sale += $item['num'];
                        $main->save();
                    }
                } else {
                    $goods->stock -= $item['num'];
                }
                $goods->save();
            }

            $pay = lang('Payment successful');
            Log::info('支付成功，支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】');
            View::assign('pay',$pay);

            return View::fetch();
        } catch (Exception $e) {
            $pay = $e->getMessage();
            View::assign('pay',$pay);
            return View::fetch();
        }
    }
}